#define INITGUID 1

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include "pntypes.h"
#include "pnresult.h"
#include "pncom.h"
#include "rmappv.h"
#include "rmaplugn.h"
#include "ppvtime.h"
#include "ppvmd5.h"
#include "ppvini.h"
#include "os.h"
extern "C" {
#include "cgi-lib.h"
#include "html-lib.h"
};
#include "ppvdemo.h"

// Local Helper Functions
int MakeRegisterUrl( char* szRegisterUrl, char* szIniCfg, char* szUserID );
int GetIniCfg( char* szIniCfg);

IRMAPPVDatabase*  g_pPPV  = NULL;

// If your database is password protected, fill in the following Username 
// and Password strings.  These strings will only be used to open the 
// database and will NOT be accessible to anyone after the cgi is built. 

const char SZ_DB_USERID[50]   = "Replace this text with database username";
const char SZ_DB_PASSWORD[50] = "Replace this text with database password";

int iDebug=0;                          //GLOBAL Variable to Control Debug 

void debug(char* debugvar,char* debugval)
   {
   FILE* dfile;

   dfile= fopen("ppvdemo.dmp", "a+"); 

   fprintf(dfile,"\n%s=(%s)",debugvar,debugval);
   fclose(dfile);
   }
 
int main()
   {
   llist 			form_input;					// linked list to hold form info
   int				nResult; 
   HINSTANCE		DLL;
   FPCREATEINSTANCE	fpCreateInstance;
   IUnknown*		pUnknown = NULL;

   char*		szCommand;
   char			szPluginName[BUF_LENGTH];
   char			szDatabase  [BUF_LENGTH];
   char			szIniCfg    [BUF_LENGTH];
   char			szBuf       [BUF_LENGTH];
   char			szDebug     [BUF_LENGTH];			

   read_cgi_input(&form_input);        // retrieve file AND form data
	
   if(!GetIniCfg( szIniCfg ) ) 	       // retrieve required INI configuration file
	   {
	   list_clear(&form_input);
       return 0;
	   }

   GetPrivateProfileString(INI_SYSTEM,INI_DEBUG,EMPTY_STRING, szBuf, sizeof( szBuf), szIniCfg );
   strcpy(szDebug,szBuf);
   if(strcmp(szDebug,"1"))
      iDebug = 1;

   if(!iDebug)
      {
      debug("===PPVDemo===","");
      debug("Debug",szDebug);
      }

	// retrieve plugin name
   GetPrivateProfileString( INI_SYSTEM, INI_PLUGIN, EMPTY_STRING, szBuf, sizeof( szBuf), szIniCfg );
   strcpy( szPluginName, szBuf );

   if(iDebug) debug("szPluginName",szPluginName);

   memset( szBuf, 0, sizeof( szBuf ) );	
   GetPrivateProfileString( INI_SYSTEM, INI_DATABASE, EMPTY_STRING, szBuf,sizeof( szBuf), szIniCfg );
   strcpy( szDatabase, szBuf );

   if(!iDebug )debug("szDatabase",szDatabase);
	
   DLL = LoadLibrary( szPluginName );
   fpCreateInstance = ( FPCREATEINSTANCE )GetProcAddress( DLL, "RMACreateInstance" );
 
   if (!fpCreateInstance )             // error checking for failure of plugin loading
	   {
	   print_begin();
	   printf("Plugin %s failed to load.",szPluginName );
	   print_end();
	   list_clear(&form_input);
  	   return 0;
	   }

   if(!iDebug )debug("szPluginName",szPluginName);

   if(PNR_OK != fpCreateInstance(&pUnknown)) 	// error checking for invalid object pointer
	   {
	   print_begin();
	   printf("Plugin %s failed to create object.", szPluginName );
	   print_end();
	   list_clear(&form_input);
  	   return 0;
	   }

   if(!iDebug ) debug("Plugin instance found","");

                                       // error checking for invalid interface
   if ( PNR_OK != pUnknown->QueryInterface( IID_IRMAPPVDatabase, (void**) &g_pPPV ) )
	   {
	   pUnknown->Release();
	   print_begin();
	   printf("Plugin %s failed to find PPVDatabase interface.", szPluginName );
	   print_end();
	   list_clear(&form_input);
  	   return 0;
	   }

   if(!iDebug )
	   debug("Interface IID_IRMAPPVDatabase found","");

                                       // Initialize Plugin 
   
   nResult = g_pPPV->InitPPVDB( szDatabase, SZ_DB_USERID, SZ_DB_PASSWORD );
   if(!iDebug )
	   debug("InitPPVDB",szDatabase);
	
	                                   // handling failure to initialize database
   if ( PNR_PPV_AUTHORIZATION_FAILED == nResult )
	   {
	   print_begin();
       printf("Error opening database. Invalid userid/password combination.");
       print_end();
       list_clear(&form_input);
       return 0;
	   }
	else
       {
       if(PNR_OK != nResult)          // handling failure to open database
	       {
		   print_begin();
		   printf("Error opening the database");
		   print_end();
		   list_clear(&form_input);
		   return 0;
	       }
       }

   if(!iDebug ) debug("DataBase Opened","");
   	                                   // retreive command
   szCommand = cgi_val( form_input, FORMNAME_COMMAND );

   if(!iDebug) debug("szCommand",szCommand);
	
   if ( 0 != szCommand )
	   {
	   if ( 0 == strcmp( szCommand, FORMVALUE_INSERTUSER )  )
		   HandleInsertUser( &form_input, szIniCfg );
	   else 
           { 
           if ( 0 == strcmp( szCommand, FORMVALUE_GRANTACCESS ) )
			   HandleGrantAccess( &form_input, szIniCfg );
	    	else 
     	       {
			   print_begin();
			   printf("Command \"%s\" unknown.", szCommand);
			   print_end();
		       }
	       }
	   }	
   else      	                       // handling missing form value; command
	   {
	   print_begin();
	   printf("Missing Command.");
	   print_end();
	   }
                                       // clear memory for form data

   if(!iDebug ) debug("Cleanup","");

   list_clear(&form_input);
   g_pPPV->Release(); 
   FreeLibrary(DLL);
   return 0;
   }

//	HandleInsertUser
//	Description:  inserts a user & password, if relevant

void HandleInsertUser(llist* form_input,char* szIniCfg) 
   {
	char*		szUserid;
	char*		szPassword;
	char		szRegisterUrl[BUF_LENGTH];
	char		szPermissionsUrl[BUF_LENGTH];
	char		szBuf[BUF_LENGTH];
	char		szAuthMode[BUF_LENGTH];
	char		szRealm[BUF_LENGTH];
   
	int			nResult;
	PPVRegLog	log_item;
	char		szNull[3] = " ";
	char		temp[2048];
	char		authKey[2048];

    if(!iDebug) debug("===Insert User===","");

	                                   // error checking for valid user ID input 
   szUserid = cgi_val(*form_input, FORMNAME_USERID );
   if ( 0 == szUserid )
       {
	   print_begin();
	   printf("A userid must be specified.");
	   print_end();
	   return;
	   }

   if(!iDebug) debug("szUserid",szUserid);

                                       // error checking for valid password input 
   szPassword = cgi_val(*form_input, FORMNAME_PASSWORD );
   if ( 0 == szPassword )
	   {
	   print_begin();
	   printf("A password must be specified.");
	   print_end();
	   return;
	   }

   if(!iDebug) debug("szPasswrd",szPassword);

	                                   // retrieve server realm
   GetPrivateProfileString( INI_SYSTEM, INI_REALM, EMPTY_STRING, szBuf, sizeof( szBuf ), szIniCfg );
   strcpy( szRealm, szBuf );

   if(!iDebug) debug("szRealm",szRealm);

	                                   // retrieve server authentication mode
   GetPrivateProfileString( INI_SYSTEM, INI_AUTHMODE, EMPTY_STRING, szBuf,sizeof(szBuf), szIniCfg);
   strcpy( szAuthMode, szBuf );

   if(!iDebug) debug("szAuthMode",szAuthMode);

	                                    // retrieve server permissions URL
   GetPrivateProfileString( INI_URLS, INI_PERMISSIONS, EMPTY_STRING, szBuf, sizeof(szBuf), szIniCfg);
   strcpy( szPermissionsUrl, szBuf );

   if(!iDebug) debug("szPermissionsUrl",szPermissionsUrl);

	                                       // construct server player registration URL
   if(0 == strcmp(szAuthMode, "0") )
      MakeRegisterUrl(szRegisterUrl,szIniCfg,szUserid);

                                       // remove user to prevent conflicts
   g_pPPV->RemoveUser(szUserid);

   //if( ==  )
   //   {      
       sprintf(temp   , "%s:%s:%s", szUserid, szRealm, szPassword);
       MD5Data(authKey, (const unsigned char *)temp, strlen(temp));
       if(!iDebug) debug("MD5Data",temp);
   //    }
   //else
   //    {
       sprintf(authKey, "%s",szPassword);
       if(!iDebug) debug("authKey",authKey);
   //    }
   nResult = g_pPPV->InsertUser(szUserid, authKey);
      
   if(PNR_OK != nResult )
	   {
	   print_begin();
	   printf("Inserting User. CGI program must have write privaleges.");
	   print_end();
	   return;
	   }
   
   if(0 == strcmp(szAuthMode, "0") )   // submit multipart header
	   {

       if(!iDebug) debug("---Display next-->",szPermissionsUrl);

	   printf("Content-type: multipart/x-mixed-replace;boundary=End\n\n");
	   printf("--End\n");              // submit audio header	                                   
	   printf("Content-type: audio/x-pn-realaudio\n\n");
	   printf("%s\n", szRegisterUrl);
	   printf("--End\n");              // submit html header
	   printf("Content-type: text/html\n\n");
       printf("<HTML> <META HTTP-EQUIV=REFRESH "
	          "CONTENT='0;URL=%s'> ", szPermissionsUrl );
	   printf("--End\n");
       printf("--End--\n");            // terminate multipart header
       return;
       }
   else
       {                               // log registration fill out the log item and send it to the database
	   log_item.nStatus = (PPVRegStatus)0;
	   log_item.pUserid = szUserid;
	   log_item.pGUID = szNull;
	   log_item.pIPAddress = szNull;
	   time(&(log_item.tRequestTime));
	   log_item.pURLRedirect = szNull;
       if ( PNR_OK != g_pPPV->LogReg(&log_item) ) 
           {
		                               // an error occurred
		   print_begin();
		   printf("Error: an internal error occurred while logging to the database.");
		   print_end();
		   return;
		   }

      if(!iDebug) debug("---Display next-->",szPermissionsUrl);

       printf("Content-type: text/html\n\n");
       printf("<html> <META HTTP-EQUIV=REFRESH "
	          "CONTENT='0;URL=%s'> ", szPermissionsUrl);
	   print_end();
	   return;
	   }
   }

// HandleGrantAccess
// Description:  grants user access 

void HandleGrantAccess(	llist* form_input,char*	szIniCfg) 
   {
   char*	szUserid;						// re userid
   char*	szPermissionType;				// re permission
   char*	szUrl;							// re url
   char*	szUrlType;						// re urltype
   char*	szPermissionLength;				// re debittime/expirestime
   char		szPermissionLengthFormatted[2048];
   char		szRedirect[128];
   char		szBuf[64];
	
   PPVPermission	permission;
   int				nResult;

   if(!iDebug) debug("===GrantAccess===","");

                                       // retrieve current directory
   GetCurrentDirectory( sizeof( szIniCfg ), szIniCfg);

   if(!iDebug) debug("szIniCfg",szIniCfg);

   GetPrivateProfileString( INI_URLS, INI_REDIRECT, EMPTY_STRING,szBuf, sizeof(szBuf), szIniCfg );
   strcpy(szRedirect,szBuf);

   if(!iDebug) debug("szRedirect",szRedirect);
	
   szUserid = cgi_val(*form_input, FORMNAME_USERID);
   if ( 0 == szUserid )
	   {
	   print_begin();
	   printf("You must specify a userid.");
	   print_end();
	   return;
	   }

   if(!iDebug) debug("szUserid",szUserid);

                                       // checks for valid url for secure directory
   szUrl = cgi_val(*form_input, FORMNAME_URL );
   if(0 == szUrl )
       {
 	   print_begin();
	   printf("You must specify an url to grant access.");
	   print_end();
	   return;
       }

   if(!iDebug) debug("szUrl",szUrl);

                                       // checks for urltype
    szUrlType = cgi_val(*form_input, FORMNAME_URLTYPE);
    if(0 == szUrlType )
       {
	   print_begin();
       printf("You must specify an urltype of 0 (file) or 1 (directory).");
       print_end();
       return;
       }
    
   if(!iDebug) debug("szUrlType",szUrlType);

	                                   // 	checks for valid urltype
   if(0 == strcmp(szUrlType, "0"))
        permission.nURLType = (PPVURLType)0;
   else 
       {
       if(0 == strcmp(szUrlType, "1"))
		   permission.nURLType = (PPVURLType)1;
       else
           {
           print_begin();
           printf("You must specify an urltype of 0 (file) or 1 (directory).");
           print_end();
           return;
           }
       }
 
                                       // checks for valid type of permission granted
   szPermissionType = cgi_val(*form_input, FORMNAME_PERMISSIONTYPE );
   if ( 0 == szPermissionType )
       {
 	   print_begin();
	   printf("You must specify a permission type.");
	   print_end();
	   return;
       }

   if(!iDebug) debug("szPermissionType",szPermissionType);
  
   if(0 == strcmp(szPermissionType, "0") )	//general access
       {
	   strcpy(permission.pURL,szUrl);
	   permission.nPermissionType = (PPVPermissionType)0;
	   permission.tExpires        = 0;
	   permission.ulDebitTime     = 0;
	
       if(!iDebug) debug("===PermissionType 0===",permission.pURL);      

                                       // TIP:  Uncomment the following to ensure that users
                                       // have access to one content piece only
       // g_pPPV->RevokeAllPermissions(szUserid);

       if(!iDebug) debug("szUserid",szUserid);

       sprintf(szBuf,"%d",permission.nPermissionType);
       if(!iDebug) debug("permission.nPermissionType",szBuf);

       sprintf(szBuf,"%d",permission.tExpires);
       if(!iDebug) debug("permission.tExpires",szBuf);

       sprintf(szBuf,"%d",permission.ulDebitTime);
       if(!iDebug) debug("permission.ulDebitTime",szBuf);

       nResult = g_pPPV->GrantPermission(szUserid, &permission);

       sprintf(szBuf,"%d",nResult);
       if(!iDebug) debug("nResult",szBuf);

       if(PNR_OK != nResult)
 	       {
	       print_begin();
	       printf("Unable to grant permission. An internal error occurred.");
	       print_end();
	       return;
	       } 
	   }
   else 
       {
       if(0 == strcmp(szPermissionType, "1") ) // expiration based access
           {
		   szPermissionLength = cgi_val(*form_input, FORMNAME_PERMISSIONLENGTH );

           if(!iDebug) debug("===PermissionType 1===","");

		   if(0 == szPermissionLength )
		       {
		       print_begin();
		       printf("You must specify an expiration time to "
        		      "grant an expiration permission.");
		       print_end();
		       return;
		       }
		   // to save the user from typing in hours, minutes, seconds.
		   strcpy(szPermissionLengthFormatted, szPermissionLength);
		   strcat(szPermissionLengthFormatted, ":00:00:00");
		   strcpy(permission.pURL, szUrl);
		   permission.nPermissionType = (PPVPermissionType)1;
		   ppvStringToTime(szPermissionLengthFormatted, &permission.tExpires);
		   permission.ulDebitTime = 0;


           if(!iDebug) debug("szPermissionLengthFormatted",szPermissionLengthFormatted);
           if(!iDebug) debug("permission.pURL",permission.pURL);
           sprintf(szBuf,"%d",permission.ulDebitTime);
           if(!iDebug) debug("permission.ulDebitTime",szBuf);
           sprintf(szBuf,"%d",permission.nPermissionType);
           if(!iDebug) debug("permission.nPermissionType",szBuf);

		
		   // TIP:  Uncomment the following to ensure that users have access to one content piece only
		   // g_pPPV->RevokeAllPermissions(szUserid);

		   nResult = g_pPPV->GrantPermission(szUserid, &permission);

           sprintf(szBuf,"%d",nResult);
           if(!iDebug) debug("nResult",szBuf);

		   if(PNR_OK != nResult )
		       {
		       print_begin();
		       printf("Unable to grant permission. An internal error "
		  		  "occurred.");
		       print_end();
		       return;
		       } 
           }
	   else
           {
           if(0 == strcmp(szPermissionType, "2") ) // debit based access, in seconds
	           {
 		       szPermissionLength  = cgi_val(*form_input, FORMNAME_PERMISSIONLENGTH );

               if(!iDebug) debug("===PermissionTyp 2===","");

		       if(0 == szPermissionLength )
		           {
		           print_begin();
		           printf("You must specify a debit time to "
		                  "grant a debit permission.");
		           print_end();
		           return;
	               }

	           if(0 >= atol(szPermissionLength) )
		           {
		           print_begin();
		           printf("You must specify a time greater than 0.");
		           print_end();
		           return;
		           }

		       strcpy(permission.pURL, szUrl);
		       permission.nPermissionType = (PPVPermissionType)2;
		       permission.tExpires = 0;
		       permission.ulDebitTime = atol(szPermissionLength);
	
		                               // TIP:  Uncomment the following to ensure that users have access to
		                               //       one content piece only g_pPPV->RevokeAllPermissions(szUserid);
               if(!iDebug) debug("szUserid",szUserid);
               if(!iDebug) debug("permission.pURL",permission.pURL);

               sprintf(szBuf,"%d",permission.nPermissionType);
               if(!iDebug) debug("permission.nPermissionType",szBuf);

               sprintf(szBuf,"%d",permission.tExpires);
               if(!iDebug) debug("permission.tExpires",szBuf);
               sprintf(szBuf,"%ld",permission.ulDebitTime);
               if(!iDebug) debug("permission.ulDebitTime",szBuf);

		       nResult = g_pPPV->GrantPermission(szUserid, &permission);

               sprintf(szBuf,"%d",nResult);
               if(!iDebug) debug("nResult",szBuf);

		       if(PNR_OK != nResult )
		           {	
			       print_begin();
			       printf("Unable to grant permission. An internal error "
				          "occurred.");
			       print_end();
			       return;
		           } 
               }
	       else
               {
               if(0 == strcmp(szPermissionType, "3") )	//credit access
                   {
		           strcpy(permission.pURL,szUrl);
	
       		       permission.nPermissionType = (PPVPermissionType)3;
		           permission.tExpires        = 0;
		           permission.ulDebitTime     = 0;

                   if(!iDebug) debug("===PermissionType 3===",permission.pURL);
	
		           //g_pPPV->RevokeAllPermissions(szUserid);
                   if(!iDebug) debug("szUserid",szUserid);

                   sprintf(szBuf,"%d",permission.nPermissionType);
                   if(!iDebug) debug("permission.nPermissionType",szBuf);

                   sprintf(szBuf,"%d",permission.tExpires);
                   if(!iDebug) debug("permission.tExpires",szBuf);

                   sprintf(szBuf,"%d",permission.ulDebitTime);
                   if(!iDebug) debug("permission.ulDebitTime",szBuf);

	               nResult = g_pPPV->GrantPermission(szUserid, &permission);

                   sprintf(szBuf,"%d",nResult);
                   if(!iDebug) debug("nResult",szBuf);

	               if(PNR_OK != nResult )
		               {
		               print_begin();
		               printf("Unable to grant permission. An internal error occurred.");
		               print_end();
		               return;
		               } 
	               }
               else
                   {
 	               print_begin();
	               printf("Not a valid permission type.");
	               print_end();
	               return;
	               }
               }
           }
       }

   if(!iDebug) debug("---Display next-->",szRedirect);
   if(!iDebug) debug("Exiting Grant Access","");

   printf("Content-type: text/html\n\n");
   printf("<html><META HTTP-EQUIV=REFRESH "
		  "CONTENT='0;URL=%s'>", szRedirect);

   return;
   }


// print_header
// Description:  print the header, title, body tags, etc

void print_begin()
   {
   html_header();	   
   printf("<HTML>\n");	
   printf("<TITLE>Pay-Per-View Demo Results</TITLE>\n");
   printf("<BODY bgcolor=\"#336699\" style=\"background-color: #336699\"> \n");
     printf("<TABLE cellspacing=\"0\" cellpadding=\"0\" border=\"0\" width=\"100&#37\" >\n");
       printf("<TR>\n");
         printf("<TD align=\"left\" valign=\"top\" bgcolor=\"#FFFFFF\">\n");
           printf("<A href=\"http://www.realnetworks.com\" target=\"_blank\">\n"); 
           printf("<IMG src=\"rn_logo.gif\" hspace=\"0\" border=\"0\" vspace=\"0\" height=\"72\">\n");
           printf("</A> \n");
         printf("</TD> \n");
       printf("</TR>\n");
     printf("</TABLE>\n");

   printf("<TABLE cellspacing=\"0\" cellpadding=\"0\" border=\"0\" width=\"100&#37\">\n");
     printf("<TR>\n");
       printf("<TD align=\"left\" valign=\"top\" bgcolor=\"#336699\"> </TD>\n");
         printf("&nbsp; \n");
       printf("</TR> \n");
   printf("</TABLE> \n");

   printf("<TABLE cellspacing=\"0\" cellpadding=\"0\" border=\"0\" width=\"100&#37\" height=\"100&#37\" bgcolor=\"#FFFFFF\" >\n");
   printf("<TR>\n");
   printf("<TD align=\"left\" valign=\"top\" bgcolor=\"#FFFFFF\" width=\"100&#37\">\n");
   printf("<BR>\n");
   printf("<FONT SIZE=\"3\" FACE=\"Verdana\" COLOR=\"red\" > <B>&nbsp;&nbsp;&nbsp;&nbsp; Error: </FONT> <FONT COLOR=\"black\" >\n");
   }

// print_end
// Description: print the footer and end body tags

void print_end()
   {
   printf("</B></FONT></TD></TR></TABLE>\n");
   printf("</BODY></HTML>");
   }

int GetIniCfg( char* szIniCfg)
   {
   char		szBuf[BUF_LENGTH];
	                                   // retrieve current directory
   GetCurrentDirectory( sizeof( szBuf ), szBuf);
   strcpy( szIniCfg, szBuf );
                                       // error checking for invalid INI configuration file
   if(strcmp( szIniCfg, EMPTY_STRING) == 0 )
       {
	   print_begin();
       printf("Configuration file \"INI_CONFIG\" not found.");
       print_end();
	   return 0;
	   }
	                                   // append slash character respective to platform
#ifdef WIN32
   strcat( szIniCfg, "\\" );
#else
   strcat( szIniCfg, "/" );
#endif
	                                   // append INI configuration file name to construct full path name
   strcat( szIniCfg, INI_CONFIG ); 
   return 1;
   }

int MakeRegisterUrl( char* szRegisterUrl, char* szIniCfg, char* szUserID )
   {
   char	szBuf[BUF_LENGTH];			// buffer variable
	
   GetPrivateProfileString( INI_URLS, INI_PROTOCOL, EMPTY_STRING, szBuf,sizeof(szBuf), szIniCfg );
   strcpy( szRegisterUrl, szBuf );
   strcat( szRegisterUrl, "://" );

   GetPrivateProfileString( INI_URLS, INI_SERVER ,EMPTY_STRING, szBuf,sizeof(szBuf), szIniCfg );
   strcat( szRegisterUrl, szBuf );
   strcat( szRegisterUrl, ":" );

   GetPrivateProfileString( INI_URLS, INI_PORT ,EMPTY_STRING, szBuf,sizeof(szBuf), szIniCfg );
   strcat( szRegisterUrl, szBuf );
   strcat( szRegisterUrl, "/" );

   GetPrivateProfileString( INI_URLS, INI_PREFIX ,EMPTY_STRING, szBuf,sizeof(szBuf), szIniCfg );
   strcat( szRegisterUrl, szBuf );
   strcat( szRegisterUrl, szUserID );
   strcat( szRegisterUrl, "!" );

   GetPrivateProfileString( INI_URLS, INI_FILE, EMPTY_STRING, szBuf,sizeof(szBuf), szIniCfg );
   strcat( szRegisterUrl, szBuf );

   if(!iDebug) debug("===MakeRegisterUrl===","");

   if(!iDebug) debug("szRegisterUrl",szRegisterUrl);


   return 1;
   }

